package com.carcenter.personnel.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.carcenter.common.constant.user.UserConstant;
import com.carcenter.common.dto.LoginDto;
import com.carcenter.common.dto.ModifyDto;
import com.carcenter.common.dto.RegisterDto;
import com.carcenter.common.dto.StaffDto;
import com.carcenter.common.exception.Assert;
import com.carcenter.common.exception.BusinessException;
import com.carcenter.common.result.Result;
import com.carcenter.common.result.enums.impl.RedisConst;
import com.carcenter.common.utils.JwtTemplate;
import com.carcenter.common.result.enums.impl.BusinessCode;
import com.carcenter.common.vo.LoginVo;
import com.carcenter.personnel.entity.Staff;
import com.carcenter.personnel.mapper.StaffMapper;
import com.carcenter.personnel.service.IStaffService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author car
 * @since 2025-07-16
 */
@Service
public class StaffServiceImpl extends ServiceImpl<StaffMapper, Staff> implements IStaffService {
    @Autowired
    private StaffMapper staffMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private JwtTemplate jwtTemplate;
    //登录
    @Override
    public LoginVo login(LoginDto loginDto) {
        // 根据用户名查询,如果电话号码为空，返回错误
        Staff staff = getOne(Wrappers.lambdaQuery(Staff.class).eq(Staff::getPhone, loginDto.getPhone()));
        Assert.error(staff==null, BusinessCode.USER_LOGIN_ERROR );
        // 根据查询的密码与用户输入的密码对比,校验
        Assert.error(!BCrypt.checkpw(loginDto.getLoginPassword(),staff.getLoginPassword()), BusinessCode.USER_LOGIN_ERROR);

        // 返回
        return LoginVo.builder()
                .id(staff.getId().longValue())
                .staffName(staff.getStaffName())
                .phone(staff.getPhone())
                .avatar(staff.getAvatar())
                .roleId(staff.getRoleId())
                .token(getToken(staff.getId().longValue()))
                .build();
    }
    // 生成token
    private String getToken(Long StaffId){
        Map<String,Object> payload = new HashMap<>();
        payload.put(UserConstant.USERID,StaffId);
        // 生成token
        String token = "Bearer "+jwtTemplate.createToken(payload);
//        String token = jwtTemplate.createToken(payload);
        stringRedisTemplate.opsForValue().set(UserConstant.USER_TOKEN + StaffId,token, Duration.ofMinutes(30));
        return token;
    }
    //验证手机号
    @Override
    public void checkPhone(RegisterDto registerDto) {
        //检查验证码
        String redisKey = "user:code:" + registerDto.getPhone();
        String codeInRedis = stringRedisTemplate.opsForValue().get(redisKey);
        Assert.error(codeInRedis==registerDto.getCode(), BusinessCode.USER_VERIFY_CODE_ERROR);
    }

    //注册
    @Override
    public Staff register(RegisterDto registerDto) {
        //校验手机号码  用户名是否存在
        Staff phoneUser = this.getOne(Wrappers.lambdaQuery(Staff.class).eq(
                Staff::getPhone, registerDto.getPhone()
        ));
        Assert.error(phoneUser!=null, BusinessCode.USER_EXISTED);
        Staff name = this.getOne(Wrappers.lambdaQuery(Staff.class).eq(
                Staff::getStaffName, registerDto.getStaffName()
        ));
        Assert.error(name!=null, BusinessCode.USER_EXISTED);

        //保存用户
        Staff staff = new Staff();
        staff.setPhone(registerDto.getPhone());
        staff.setStaffName(registerDto.getStaffName());
        if (registerDto.getAccount() == null || registerDto.getAccount().equals("")){
            String staffNamePinyin = toUpperCasePinyin(registerDto.getStaffName());
            registerDto.setAccount(staffNamePinyin+"_"+ RandomUtil.randomNumbers(4));
        }
        staff.setStaffAccount(registerDto.getAccount());
        staff.setRoleId(2);
        staff.setStoreId(registerDto.getStoreId());

        //用hutool 工具进行加密
        String pwd = BCrypt.hashpw(registerDto.getPwd());
        staff.setLoginPassword(pwd);

        staff.setAccountType("普通用户");
        staff.setAccountStatus("正常");
        this.save(staff);
        return staff;
    }
    public static String toUpperCasePinyin(String chinese) {
        StringBuilder sb = new StringBuilder();
        for (char c : chinese.toCharArray()) {
            // 跳过空格字符
            if (Character.isWhitespace(c)) {
                continue;
            }
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
            if (pinyinArray != null) {
                // 取第一个发音并转换为大写，同时去掉声调数字
                String pinyin = pinyinArray[0].replaceAll("\\d", "").toUpperCase();
                sb.append(pinyin);
            } else {
                // 如果不是汉字，则直接追加该字符的大写形式（如果需要的话）
                sb.append(Character.toUpperCase(c));
            }
        }
        return sb.toString();
    }
    //员工分页
    @Override
    @Cacheable(cacheNames = RedisConst.STAFF_LIST, keyGenerator = "keyGenerator")
    public Page<Staff> getStaffDetail(Integer pageNum, Integer pageSize, StaffDto staffDto) {
        LambdaQueryWrapper<Staff> lambda = new LambdaQueryWrapper<>();

        // 关键字搜索
        if (StringUtils.isNotBlank(staffDto.getKey())) {
            lambda.and(w -> w
                    .like(Staff::getStaffName, staffDto.getKey())
                    .or()
                    .like(Staff::getStaffAccount, staffDto.getKey())
            );
        }
        Page<Staff> page = new Page<>(pageNum,pageSize);
        return staffMapper.selectPage(page,lambda);

    }


    @Override
    public void modifyPassword(Integer id, ModifyDto modifyDto) {
        //传入旧密码和新密码，将旧密码与数据库中对应的解密后的密码进行比对，比对成功将新密码加密修改到数据库
        Staff staff = getOne(Wrappers.lambdaQuery(Staff.class).eq(Staff::getId, id));
        Assert.error(!BCrypt.checkpw(modifyDto.getCurrentPassword(),staff.getLoginPassword()), BusinessCode.PASSWORD_ERROR);
        staff.setLoginPassword(BCrypt.hashpw(modifyDto.getNewPassword()));
        updateById(staff);

    }

    @Override
    @CacheEvict(cacheNames = RedisConst.STAFF_LIST, keyGenerator = "keyGenerator")
    public void updateStaff(Staff staff) {
        this.updateById(staff);
    }

    @Override
    @CacheEvict(cacheNames = RedisConst.STAFF_LIST, keyGenerator = "keyGenerator")
    public void removeStaff(Integer id) {
        this.removeById(id);
    }
}
